https://leetcode.com/problems/erect-the-fence/
你有n棵樹的座標,請你用柵欄把樹全部圍起來,因為柵欄太貴了所以請圍出最短的距離
這題簡單來說就是凸包(convex hull)的問題
這個解法是Jarvis' March又叫做禮物包裝演算法(Gift Wrapping Algorithm),概念是先找出最外側的任意點,之後用外積找出其他也是最外側的點,總之先上程式碼吧!
class Solution:
    def outerTrees(self, trees: List[List[int]]) -> List[List[int]]:
        if len(trees) <= 3:
            return trees
        
        start = self.find_start_pos(trees)
        hull = []
        p = start
        q = 0
        
        while True:
            
            q = (p + 1) % len(trees)
            
            for i in range(len(trees)):
                if self.orientation(trees[p], trees[i], trees[q]) < 0: 
                # i在逆時鐘方向,可以當作最外圈的候選
                    q = i
            
            for i in range(len(trees)):
                if i != p and i != q and self.orientation(trees[p], trees[i], trees[q]) == 0: 
                # 同一條線上
                    x = trees[p][0] <= trees[i][0] and trees[i][0] <= trees[q][0] \
                            or trees[p][0] >= trees[i][0] and trees[i][0] >= trees[q][0]
                    y = trees[p][1] <= trees[i][1] and trees[i][1] <= trees[q][1] \
                            or trees[p][1] >= trees[i][1] and trees[i][1] >= trees[q][1]
                    
                    if x and y:
                        hull.append(trees[i]);
                    
            hull.append(trees[q])
            p = q
            
            if p == start:
                break
        
        return hull
    
    def find_start_pos(self, trees):
        # 找起始的點
        start = 0
        for i, tree in enumerate(trees):
            if math.sqrt(tree[0]**2 + tree[1]**2) < math.sqrt(trees[start][0]**2 + trees[start][1]**2):
                start = i
                
        return start
    
    def orientation(self, p, q, r):
        #外積
        return (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]) 
這個方法的時間複查度是 O(mn),m代表最外圈有幾個點,如果最外圈點很多的話就會超過系統限制的時間
今天的題目對我來說很難,之前沒有接觸過凸包的問題,所以學到新東西了
解法1的時間會超過系統要求的限制,所以要用其他的演算法
但是,我懶了
過幾天後再補上OK的解法吧!